<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html>
<head>
<title>Erste Programme in PyQt4</title>
<link rel="stylesheet" href="../format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="PyQt, PyQt4, First programs, tutorial, python, Linux">
<meta name="description" content="Erste Programme in PyQt4">
<meta name="language" content="de">
<meta name="author" content="ján bodnár">
<meta name="distribution" content="global">
<meta name="translation" content="manuel stein">
</head>

<body>

<div class="content">


<a href="/" title="Home">Home</a>&nbsp;
<a href=".." title="Home">Contents</a>

<h1>Erste Programme in PyQt4</h1>

<p>
In diesem Abschnitt des PyQt4-Tutorials lernen wir etwas über grundlegende Funktionen. 
Dabei wird so langsam erklärt, als wenn man mit einem Kinde sprechen würde. Die ersten Schritte 
eines Kindes sind unbeholfen - genau so ist es auch für einen Programmieranfänger. 
Erinnern Sie sich: Es gibt keine dummen Menschen - nur faule und solche, 
die nicht ausdauernd genug sind.
</p>

<h3>Einfaches Beispiel</h3>

<p>
Das folgende Codebeispiel ist sehr vereinfacht. Es zeigt lediglich ein kleines 
Fenster. Und doch können wir bereits eine Menge mit diesem Fenster machen: 
Wir können seine Größe ändern, vergrößern und verkleinern. Dafür braucht es 
eine Menge Code. Jemand hat das bereits übernommen. Weil es sich diese 
Funktionalität in den meisten Anwendungen wiederholt, macht es keinen Sinn, 
es immer und immer wieder zu schreiben. Darum wurde es vor dem Programmierer 
versteckt. Python ist ein Toolset auf hoher Ebene. Würden wir mit einem 
Toolkit niedrigerer Ebene programmieren, würde das folgende Codebeispiel 
leicht Dutzende Zeilen umfassen.
</p>

<pre class="code">
#!/usr/bin/python

# simple.py

import sys
from PyQt4 import QtGui

app = QtGui.QApplication(sys.argv)

widget = QtGui.QWidget()
widget.resize(250, 150)
widget.setWindowTitle('simple')
widget.show()

sys.exit(app.exec_())
</pre>

<pre class="code">
 import sys
 from PyQt4 import QtGui
</pre>

<p>
Hier nehmen wir die nötigen Importe vor. Die grundlegenden GUI-Widgets befinden sich im <em>QtGui</em>-Modul.
</p>

<pre class="explanation">
app = QtGui.QApplication(sys.argv)
</pre>

<p>
<strong>Jede</strong> PyQt4-Anwendung muss ein application-Objekt erzeugen. Das <em>application</em>-Objekt befindet sich im QtGui-Modul. Der <em>sys.argv</em>-Parameter ist eine Liste von Argumenten von der Kommandozeile. Python-Skripte können über die Shell (Kommandozeile) gestartet werden. Auf diese Weise können wir den Aufruf unserer Skripte kontrollieren.
</p>

<pre class="explanation">
 widget = QtGui.QWidget()
</pre>

<p>
Das QWidget-Widget ist die Basisklasse aller Benutzeroberflächenobjekte in PyQt4. Wir verwenden den Default-Konstruktor von QWidget. Der Default-Konstruktor hat keine Elternklasse  (parent). Ein Widget ohne Elternklasse heißt <em>Fenster</em>.
</p>

<pre class="explanation">
 widget.resize(250, 150)
</pre>

<p>
Die <em>resize()</em>-Methode passt die Widget-Größe an. Sie beträgt 250px in der Breite und 150px in der Höhe.
</p>

<pre class="explanation">
 widget.setWindowTitle('simple')
</pre>

<p>
Hier setzen wir den Titel unseres Fensters, der jetzt in der Titelzeile angezeigt wird.
</p>


<pre class="explanation">
widget.show()
</pre>

<p>
Die <em>show()</em>-Methode zeigt das Widget auf dem Bildschirm an.
</p>

<pre class="explanation">
 sys.exit(app.exec_())
</pre>

<p>
Zum Schluss betreten wir die Hauptschleife der Anwendung. Die Event-Behandlung beginnt an dieser Stelle. Die Hauptschleife empfängt Events vom Windowsystem und überträgt sie an die Anwendungswidgets. Die Hauptschleife endet, wenn wir die <em>exit()</em>-Methode aufrufen oder das Hauptwidget zerstört wird. Die <em>sys.exit()</em>-Methode garantiert eine saubere Beendigung. Die Umgebung wird informiert, wie die Anwendung beendet wurde.
</p>

<p>
Fragen Sie sich, warum die <em>exec_()</em>-Methode einen Unterstrich hat? Alles hat seine Bedeutung. Offensichtlich hat sie ihn, da es sich bei exec um ein Python Schlüsselwort handelt. Darum wurde hier statt dessen <em>exec_()</em> verwendet.
</p>

<img src="../images/simple.jpg" alt="Simple" />
<p class="figure">Abbildung: Einfaches Beispiel</p>

<h3>Ein Anwendungs-Icon</h3>

<p>
Das Anwendungs-Icon ist ein kleines Bild, das gewöhnlich in der linken oberen Ecke der Titelzeile angezeigt wird. Das folgende Beispiel zeigt, wie das in PyQt4 gemacht wird. Wir werden darüber hinaus einige neue Methoden kennenlernen.
</p>

<pre class="code">
#!/usr/bin/python

# icon.py

import sys
from PyQt4 import QtGui


class Icon(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Icon')
        self.setWindowIcon(QtGui.QIcon('icons/web.png'))


app = QtGui.QApplication(sys.argv)
icon = Icon()
icon.show()
sys.exit(app.exec_())
</pre>

<p>
Das Beispiel wurde im prozeduralen Stil geschrieben. Die Python Programmiersprache unterstützt sowohl prozeduralen als auch objektorientierten Programmierstil. In PyQt4 zu programmieren, setzt objektorientiertes Programmieren (OOP) voraus.
</p>

<pre class="explanation">
 class Icon(QtGui.QWidget):
     def __init__(self, parent=None):
         QtGui.QWidget.__init__(self, parent)
</pre>

<p>
Die drei wichtigsten Dinge beim <acronym title="Objektorientiertes Programmieren">OOP</acronym> sind Klassen, Eigenschaften und Methoden. Im Beispiel erzeugen wir eine neue Klasse names <em>Icon</em>. Die Icon-Klasse erbt von der QtGui.QWidget-Klasse. Das bedeutet, dass wir zwei Konstruktoren aufrufen müssen. Die erste für die Icon-Klasse, die zweite für die geerbte Klasse.
</p>

<pre class="explanation">
 self.setGeometry(300, 300, 250, 150)
 self.setWindowTitle('Icon')
 self.setWindowIcon(QtGui.QIcon('icons/web.png'))
</pre>

<p>
Alle drei Methoden wurden von der QtGui.QWidget-Klasse geerbt. Die <em>setGeometry()</em>-Methode macht zwei Dinge: Sie lokalisiert das Fenster auf dem Bildschirm und setzt die Fenstergröße. Die ersten zwei Parameter sind die x- und y-Positionen des Fensters. Die dritte erfasst die Weite, die vierte seine Höhe. Die letzte Methode bestimmt das Anwendungs-Icon. Dazu haben wir eine <em>QIcon</em>-Objekt erzeugt, das den Pfad zu unserem anzuzeigenden Icon erhält.
</p>

<img src="../images/icon.jpg" alt="Icon" />
<p class="figure">Abbildung: Icon</p>

<h3>Anzeige eines Tooltips</h3>

<p>
Wir können für jedes unserer Widgets eine Ballon-Hilfe erzeugen.
</p>

<pre class="code">
#!/usr/bin/python

# tooltip.py

import sys
from PyQt4 import QtGui
from PyQt4 import QtCore


class Tooltip(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Tooltip')

        self.setToolTip('This is a &lt;b&gt;QWidget&lt;/b&gt; widget')
        QtGui.QToolTip.setFont(QtGui.QFont('OldEnglish', 10))


app = QtGui.QApplication(sys.argv)
tooltip = Tooltip()
tooltip.show()
sys.exit(app.exec_())
</pre>

<p>
In diesem Beispiel zeigen wir einen Tooltip für ein <em>QWidget</em>-Widget.
</p>

<pre class="explanation">
 self.setToolTip('This is a &lt;b&gt;QWidget&lt;/b&gt; widget')
</pre>

<p>
Um einen Tooltip zu erzeugen, rufen wir die <em>setTooltip()</em>-Methode auf. Wir können dabei Richt-Text-Formatierung verwenden.
</p>

<pre class="explanation">
 QtGui.QToolTip.setFont(QtGui.QFont('OldEnglish', 10))
</pre>

<p>
Da die Standardschrift des <em>QToolTip</em> nicht gut aussieht, ändern wir diese.
</p>

<img src="../images/tooltip.jpg" alt="Tooltip">
<p class="figure">Abbildung: Tooltip</p>


<h3>Schließen eines Fensters</h3>

<p>
Der offensichtliche Weg, ein Fenster zu schließen, ist, auf die x-Schaltfläche in der Titelzeile zu klicken. Im nächsten Beispiel wollen wir zeigen, wie man über das Programm selbst unser Fenster schließen kann. Wir werden dabei kurz auf Signale und Slots eingehen.
</p>

<p>
Als nächstes kommt der Konstruktor eines QPushButton, den wir in unserem Beispiel verwenden werden.
</p>

<pre class="definition">
 QPushButton(string text, QWidget parent = None)
</pre>

<p>
Der <em>text</em>-Parameter ist der Schriftzug, der auf dem Knopf angezeigt wird.  Bei <em>parent</em> handelt es sich um das Herkunftsobjekt, auf dem unser Knopf platziert wird - in diesem Fall das QWidget.
</p>

<pre class="code">
#!/usr/bin/python

# quitbutton.py

import sys
from PyQt4 import QtGui, QtCore


class QuitButton(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Quit button')

        quit = QtGui.QPushButton('Close', self)
        quit.setGeometry(10, 10, 60, 35)

        self.connect(quit, QtCore.SIGNAL('clicked()'),
            QtGui.qApp, QtCore.SLOT('quit()'))


app = QtGui.QApplication(sys.argv)
qb = QuitButton()
qb.show()
sys.exit(app.exec_())
</pre>

<pre class="explanation">
 quit = QtGui.QPushButton('Close', self)
 quit.setGeometry(10, 10, 60, 35)
</pre>

<p>
Wir erzeugen einen Druckknopf und positionieren ihn auf dem QWidget auf dieselbe Weise, wie wir es vorher mit dem Widget selbst auf dem Bildschirm getan haben.
</p>

<pre class="explanation">
 self.connect(quit, QtCore.SIGNAL('clicked()'),
     QtGui.qApp, QtCore.SLOT('quit()'))
</pre>

<p>
Das Ereignisverarbeitungssystem funktioniert in PyQt4 mit einem Signal&amp;Slot-Mechanismus. 
Wenn wir auf den Knopf drücken, wird das Signal <em>clicked()</em> geworfen. 
Der Slot kann ein PyQt-Slot sein oder jeder Pythonaufruf. Die <em>QtCore.QObject.connect()</em>-Methode 
verbindet Signale mit Slots. In unserem Fall ist der Slot ein vordefinierter PyQt-<em>quit()</em>-Slot. 
Die Kommunikation findet zwischen zwei Objekten, nämlich dem Sender und dem Empfänger, statt. 
Der Sender ist der Druckknopf, der Empfänger das Anwendungsobjekt.
</p>

<img src="../images/quitbutton.jpg" alt="Beenden-Knopf" />
<p class="figure">Abbildung: Beenden-Schaltfläche</p>

<h3>Mitteilungsbox</h3>

<p>
Standardmäßig schließt sich das QWidget, wenn wir den x-Knopf in der 
Titelzeile anklicken. Manchmal wollen wir dieses Standardverhalten ändern. 
Zum Beispiel, wenn wir eine Datei in einem Editor geöffnet und geändert haben. 
Wir zeigen eine Mitteilungsbox, um die Aktion bestätigen zu lassen.
</p>

<pre class="code">
#!/usr/bin/python

# messagebox.py

import sys
from PyQt4 import QtGui


class MessageBox(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('message box')


    def closeEvent(self, event):
        reply = QtGui.QMessageBox.question(self, 'Message',
            "Are you sure to quit?", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)

        if reply == QtGui.QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

app = QtGui.QApplication(sys.argv)
qb = MessageBox()
qb.show()
sys.exit(app.exec_())
</pre>

<p>
Wenn wir das QWidget schließen, wird das <em>QCloseEvent</em> erzeugt. Um das Widgetverhalten zu verändern, müssen wir den <em>event()</em> Eventhandler überschreiben.
</p>

<pre class="explanation">
 reply = QtGui.QMessageBox.question(self, 'Message',
     "Are you sure to quit?", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
</pre>

<p>
Wir zeigen eine Mitteilungsbox mit zwei Knöpfen - Ja und Nein. Der erste String erscheint in der Titelzeile, der zweite ist die Nachricht, die vom Dialog angezeigt wird. Der Rückgabewert wird in der reply-Variablen gespeichert.
</p>

<pre class="explanation">
 if reply == QtGui.QMessageBox.Yes:
     event.accept()
 else:
    event.ignore()
</pre>

<p>
Hier prüfen wir den Rückgabewert. Wenn wir den Ja-Knopf anwählen, 
nehmen wir das Ereignis an, was uns zum Schließen des Widgets führt 
und zur Beendigung der Anwendung. Andernfalls ignorieren wir das close-Ereignis.
</p>


<img src="../images/messagebox.jpg" alt="Mitteilungsbox" />
<p class="figure">Abbildung: Mitteilungsbox</p>


<h3>Fensterzentrierung auf dem Bildschirm</h3>

<p>
Das folgende Skript zeigt, wie man ein Fenster auf einer Desktopoberfläche zentrieren kann.
</p>

<pre class="code">
#!/usr/bin/python

# center.py

import sys
from PyQt4 import QtGui


class Center(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setWindowTitle('center')
        self.resize(250, 150)
        self.center()

    def center(self):
        screen = QtGui.QDesktopWidget().screenGeometry()
        size =  self.geometry()
        self.move((screen.width()-size.width())/2, (screen.height()-size.height())/2)


app = QtGui.QApplication(sys.argv)
qb = Center()
qb.show()
sys.exit(app.exec_())
</pre>

<pre class="explanation">
 self.resize(250, 150)
</pre>

<p>
An dieser Stelle wird das QWidget auf 250px Breite und 150px Höhe eingestellt.
</p>

<pre class="explanation">
 screen = QtGui.QDesktopWidget().screenGeometry()
</pre>

<p>
Wir finden die Bildschirmauflösung des Monitors heraus.
</p>

<pre class="explanation">
 size =  self.geometry()
</pre>

<p>
Hier holen wir uns die Größe unseres QWidgets.
</p>

<pre class="explanation">
 self.move((screen.width()-size.width())/2, (screen.height()-size.height())/2)
</pre>

<p>
Hier bewegen wir das Fenster in die Mitte des Bildschirms.
</p>

<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified September 11, 2007  <span class="copyright">&copy; 2007 - 2011 Jan Bodnar</span>
<span class="copyright">Translation © 2009 Manuel Stein</span>
</div>
</div>

</div> <!-- content -->
</body>
</html>

